/*
 * @Author: wuqingchun
 * @Date: 2024-04-12 13:48:46
 * @Description: 字符串类实现
 * @LastEditors: wuqingchun
 * @LastEditTime: 2024-04-15 09:09:18
 */
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>


/**
 * @brief 字符串类实现
 * 
 */
class MyString
{
    /**
     * @brief 友元函数，实现类的输出流功能
     * 友元函数可以直接访问类的私有成员，它是定义在类外部的普通函数，不属于任何类，但需要类的内部声明，声明需要加friend关键字。
     */
    friend std::ostream& operator<<(std::ostream& refOStream, const MyString& refStr);
private:
    /* data */
public:
    // 默认构造函数（constructor）
    MyString(/* args */)
    {
        std::cout << "MyString()" << std::endl;
    }

    MyString(const char* pcStr)
    {
        std::cout << "MyString(const char *pcStr)" << std::endl;
        if (pcStr == nullptr)
        {
            return;
        }

        size_t ulLen = strlen(pcStr);
        char* pcTemp = new (std::nothrow) char[ulLen + 1];
        if (pcTemp != nullptr)
        {
            memcpy(pcTemp, pcStr, ulLen);
            pcTemp[ulLen] = '\0';

            m_pcStr = pcTemp;
            m_ulSize = ulLen;
        }
    }

    // 拷贝构造函数(如果没有实现，编译器会提供一个默认的拷贝构造函数==>浅拷贝)
    // 对于包含资源的类，需要进行资源的深度拷贝，默认构造函数不能满足要求
    // 当使用已存在的对象来初始化新对象时，拷贝构造函数会被调用。
    MyString(const MyString& refStr)
    {
        std::cout << "MyString(const MyString& refStr)" << std::endl;
        //m_pcStr = refStr.m_pcStr;
        //m_ulSize = refStr.m_ulSize;

        if (refStr.m_pcStr != nullptr)
        {
            __CreateNewStr(refStr.m_pcStr, refStr.m_ulSize);
        }
    }

    // 赋值运算符
    // 赋值运算符=的重载允许我们自定义对象赋值的行为。当我们使用=将一个对象赋值给另一个已存在的对象时，赋值运算符重载函数会被调用。
    MyString& operator=(const MyString& refOther)
    {
        std::cout << "MyString operator=(const MyString& refStr)" << std::endl;
        
        // 避免自己给自己赋值（自赋值）
        if (this == &refOther)
        {
            return *this;
        }

        if (m_pcStr != nullptr)
        {
            delete [] m_pcStr;
        }

        __CreateNewStr(refOther.m_pcStr, refOther.m_ulSize);

        return *this;
    }

    // 移动构造函数
    /**
     * @brief Construct a new My String object
     * 移动构造函数
     * @param refStr 右值引用
     */
    MyString(MyString&& refStr)
    {
        std::cout << "MyString(MyString&& refStr)" << std::endl;

        if (m_pcStr != nullptr)
        {
            delete [] m_pcStr;
        }

        m_pcStr = refStr.m_pcStr;
        m_ulSize = refStr.m_ulSize;
        refStr.m_pcStr = nullptr;
        refStr.m_ulSize = 0;
    }

    // 移动赋值运算符
    MyString& operator=(MyString&& refStr)
    {
        std::cout << "MyString& operator=(MyString&& refStr)" << std::endl;

        if (this == &refStr)
        {
            return *this;
        }

        if (m_pcStr != nullptr)
        {
            delete [] m_pcStr;
        }

        m_pcStr = refStr.m_pcStr;
        m_ulSize = refStr.m_ulSize;
        refStr.m_pcStr = nullptr;
        refStr.m_ulSize = 0;

        return *this;
    }

    // 析构函数（destructor)
    ~MyString()
    {
        if (m_pcStr != nullptr)
        {
            delete [] m_pcStr;
            m_pcStr = nullptr;
            m_ulSize = 0;
        }
    }

    size_t length() const
    {
        return m_ulSize;
    }

    size_t capacity() const
    {
        return m_ulSize;
    }

    size_t max_size() const
    {
        return m_ulSize;
    }
private:
    void __CreateNewStr(const char* pcSrc, size_t ulSize)
    {
        char* pcTemp = new (std::nothrow) char[ulSize + 1];
        if (pcTemp != nullptr)
        {
            memcpy(pcTemp, pcSrc, ulSize + 1);
            m_pcStr = pcTemp;
            m_ulSize = ulSize;
        }
    }
private:
    char* m_pcStr {nullptr};
    size_t m_ulSize {0};
};


std::ostream& operator<<(std::ostream& refOStream, const MyString& refStr)
{
    refOStream << refStr.m_pcStr;

    //refOStream <<"pcStr: " << refStr.m_pcStr << ", size: " << refStr.m_ulSize;
    return refOStream;
}
template <typename T>
void show(const T& refStr)
{
    std::cout << "content: " << refStr << std::endl;
    std::cout << "length: " << refStr.length() << std::endl;
    std::cout << "capacity: " << refStr.capacity() << std::endl;
    std::cout << "max_size: " << refStr.max_size() << std::endl;
}

void test_std_string()
{
    std::cout << "================standard string begin==================" << std::endl;
    std::string strUnInit;
    show(strUnInit);

    //std::string strNullptr(nullptr); // throw exception
    //std::cout << strNullptr << std::endl;
    
    std::string strNone("");
    show(strNone);

    std::string strData1("Hello World!");
    show(strData1);

    std::string strData2 = strData1; // 调用拷贝构造函数，类似于 std::string strData2(strData1);
    show(strData2);

    std::string strData3;
    strData3 = strData2;        // 调用赋值运算符
    show(strData3);

    std::string strData4(std::move(strData3)); // 调用移动构造函数
    show(strData4);
    // strData3 不可用状态
    //show(strData3);

    std::string strData5;
    strData5 = std::move(strData4); // 调用移动赋值运算符
    // strData4 不可用状态
    // show(strData4);

    std::cout << "================standard string end===================" << std::endl;
}

void test_mystring()
{
    std::cout << "\n================standard mystring begin==================" << std::endl;

    MyString strUnInit;
    //show(strUnInit);

    MyString strNull(nullptr);
    //std::cout << strNull << std::endl;

    MyString strNone("");
    show(strNone);

    MyString strData1("Hello World!");
    show(strData1);

    MyString strData2 = strData1; // 调用拷贝构造函数，类似于 MyString strData2(strData1);
    show(strData2);

    MyString strData3;
    strData3 = strData2;        // 调用赋值运算符
    show(strData3);

    MyString strData4(std::move(strData3)); // 调用移动构造函数
    show(strData4);
    // strData3 不可用状态
    //show(strData3);

    MyString strData5;
    strData5 = std::move(strData4); // 调用移动赋值运算符
    // strData4 不可用状态
    // show(strData4);

    std::cout << "================standard mystring end===================" << std::endl;
}

int main(int argc, char** argv)
{
    test_std_string();

    test_mystring();

    return 0;
}